# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
# Description:                                                          #
# This is a Cython binding for the Boost Interval Library.              #
#                                                                       #
# Author:                                                               #
#     Harald Schilly - harald.schilly@gmail.com                         #
#     2008, Vienna, Austria                                             #
#                                                                       #
# Copyright: ALL RIGHTS RESERVED                                        #
# License:   GPL v2+ (http://www.gnu.org/licenses/gpl-2.0.html)         #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #  

from pyBoostInterval cimport *

#Note: tests showed, cpdef double func(...):return is faster than def func():return ...

cdef class Interval:
    """
    Python Class for Cython Binding to the Boost Interval Library.
    Used interval structure is
       typedef interval <double,
                         policies<save_state<rounded_transc_opp<double> >,
                         checking_base<double> > > IVD;
    """

    cdef IVD *_iv
    cpdef assign(self, double l, double u):
        self._iv.assign(l,u)
    cpdef set(self, Interval i):
        self._iv.assign(i._iv.lower(), i._iv.upper())
#    cdef _new(self, IVD *i):
#        del_IVD(self._iv)
#        self._iv = i
    def __cinit__(self, double x1, double x2):
        self._iv = new_IVD_2(x1,x2)
    def __dealloc__(self):
        del_IVD(self._iv)
    def __repr__(self):
        return '[%s ~ %s]'%(self._iv.lower(), self._iv.upper())

    ### information
    cpdef double lower(self):
        return self._iv.lower()
    cpdef double upper(self):
        return self._iv.upper()
    cpdef bint isSingleton(self):
        return singleton(self._iv)
    cpdef double median(self):
        return median_c(self._iv)
    cpdef double width(self):
        return width_c(self._iv)

    ### set operations
    cpdef Interval intersect(self, Interval other):
        return intersect(self, other)
    cpdef bisect(self, depth = 1):
        return bisect(self, depth)
    cpdef overlap(self, Interval other):
        return overlap_c(self._iv, other._iv)
    
    ### zero-ary functions
    cpdef Interval square(self):
        return square(self)

    ### unary functions
    cpdef Interval widen(self, double w):
        return widen(self, w)

    ### binary operations
    def __add__(l, r):
        return add_op(l, r)
    def __sub__(l, r):
        return sub_op(l, r)
    def __mul__( l, r):
        return mul_op(l, r)
    def __div__(l, r):
        return div_op(l, r)
    def __pow__(b, e, modulo):
        return pow_op(b, e)

    def __contains__(l, Interval r):
        if isinstance(l, float):
           return in_c(l, r._iv)
        else:
           return subset_c(r._iv, l._iv)

#helper
cdef Interval build_c(IVD ivd):
    return Interval(ivd.lower(), ivd.upper())


### information

cpdef double width(Interval i):
    return width_c(i._iv)

cpdef double median(Interval i):
    return median_c(i._iv)

cpdef bint isSingleton(Interval i):
   return singleton(i._iv)


### unary operations

cpdef Interval sqrt(Interval i):
    return build_c(sqrt_c(i._iv))

cpdef Interval sin(Interval i):
    return build_c(sin_c(i._iv))

cpdef Interval cos(Interval i):
    return build_c(cos_c(i._iv))

cpdef Interval tan(Interval i):
    return build_c(tan_c(i._iv))

cpdef Interval square(Interval i):
    return build_c(square_c(i._iv))

### unary operations
cpdef Interval widen(Interval i, double w):
    return build_c(widen_c(i._iv, w))


### set operations
cpdef Interval intersect(Interval a, Interval b):
    return build_c(intersect_c(a._iv, b._iv))

cpdef bint overlap(Interval a, Interval b):
    return overlap_c(a._iv, b._iv)

cpdef bisect(Interval iv, int n = 1):
    il = [iv]
    cdef i_pair ip
    for 1 <= i <= n:
        il_tmp = []
        for ivl in il:
            ip = bisect_c((<Interval>ivl)._iv)
            il_tmp.append(Interval(ip.first.lower(), ip.first.upper()))
            il_tmp.append(Interval(ip.second.lower(), ip.second.upper()))
        il = il_tmp
    return il


### binary operations
cdef Interval add_op(Interval l, Interval r):
    return build_c(add_op_c(l._iv, r._iv))

cdef Interval sub_op(Interval l, Interval r):
    return build_c(sub_op_c(l._iv, r._iv))

cdef Interval mul_op(Interval l, Interval r):
    return build_c(mul_op_c(l._iv, r._iv))

cdef Interval div_op(Interval l, Interval r):
    return build_c(div_op_c(l._iv, r._iv))

cdef Interval pow_op(Interval b, int e):
    return build_c(pow_op_c(b._iv, e))

